package com.fingard.dsp.bank.directbank.icbc11;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringReader;
import java.security.PrivateKey;
import java.text.MessageFormat;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directbank.FailCode;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatPayRec;
import com.fingard.dsp.bank.directbank.icbc11.util.FileEncryptionTest;
import com.fingard.dsp.bank.directbank.icbc11.util.ICBC11SignUtil;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.detail.RetAtsBatPayRecDetail;
import com.fingard.io.FileHelper;
import com.fingard.net.ConnState;
import com.fingard.net.FtpPortClient;
import com.fingard.net.FtpReceiver;
import com.fingard.net.SftpPortClient;
import com.fingard.text.StringHelper;
import com.fingard.dsp.bank.directbank.icbc11.util.FileEncryptionTest;


/**
 * 工行银保通(行内准实时批量代收付接口)
 * 
 * 需求描述:
 * 		1、通讯方式:FTP或者SFTP
 * 		2、交互内容:*.txt文件
 * 		3、交互字符集：GBK
 * 
 * 渠道说明:
 * 		本接口适用于采用准实时批量代收付业务的场景，
 * 		文件处理时间窗为[00:30,06:30],[09:00-23:30]，
 * 		具体上送时间点不再限制，回盘文件会准实时返回，最快可以在1个小时内回盘，实际回盘时间会根据队列深度返回时间会有差异
 * 		控制文件大小，一个文件需控制在2万行的明细记录之内，如果业务数据超过2万，建议按照2万一个文件进行分拆上送
 * 
 * @author Cruise
 * @date 2018年8月25日
 */
public class ICBC11BatPayRec extends ICBC11Base implements IBatPayRec {
	@Override
	public RetAtsBatPayRec d_1988_BatPay(ReqBatPayRec p_req1988) throws Exception {
		return d_BatPayRec(p_req1988);
	}

	@Override
	public RetAtsQryBatPayRec d_1998_QryBatPay(ReqQryBatPayRec p_req1998) throws Exception {
		return d_QryBatPayRec(p_req1998);
	}

	@Override
	public RetAtsBatPayRec d_9188_BatPay(ReqBatPayRec p_req9188) throws Exception {
		return d_BatPayRec(p_req9188);
	}

	@Override
	public RetAtsQryBatPayRec d_9198_QryBatPay(ReqQryBatPayRec p_req9198) throws Exception {
		return d_QryBatPayRec(p_req9198);
	}

	/**
	 * 批量代收付提交
	 * 
	 * <p>功能描述:</p>
	 * <ul>
	 * 	<li>1、文件名命名规则:</li>
	 * 		<li>ENY(3位)+IAAS(4位)+保险公司代码（3位）+地区号(5位)+网点号(5位)+代理业务编号(9位)+ YYYYMMDD(日期8位)+ AGENT(5位)+批次(10位)+ATS.txt</li>
	 *  <li>2、文件内容格式说明:</li>
	 *  <li>1)  汇总记录：</li>
	 *  	<li>文件借(贷)总笔数|文件借(贷)总金额(单位:分)|数字签名串\n</li>
	 *  <li>2)  明细记录：</li>
	 *  	<li>序列号(20位)|客户账号|客户账号户名|交易金额(单位:分)|借贷标志(1借,2贷)|摘要|是否银保通保单(1是,0否)|保单号|业务类型|委托代扣代付协议号\n</li>
	 * </ul>
	 * 
	 * @param p_reqBat 批量代收付请求对象
	 * @return 批量代收付响应对象
	 * @throws Exception
	 */
	public RetAtsBatPayRec d_BatPayRec(ReqBatPayRec p_reqBat) throws Exception {
		RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_reqBat.reqHeader);
		retAts.reqSeqID = p_reqBat.reqBatchNO;
		
    	boolean IsNewSequence  = getBankConfig().getValueAsBool("IsNewSequence");
		String tmpPaySendDate = Format.Date8Format.format(p_reqBat.getPayDateTime());


		try {
			ActSetItem actItem = this.getBankConfig().getActSetItem(p_reqBat.ownAct, "bat");
			if (actItem == null) {
				retAts.respCode = "0";
				retAts.respInfo = "未找到账号:[" + p_reqBat.ownAct + "]商户配置信息!";
				retAts.reqSeqID = p_reqBat.reqBatchNO;
				retAts.transState = PaymentState.FAIL_Batch;
				retAts.payInfoCode = FailCode.E9981;
				retAts.writeRetToATS();
				return retAts;
			}
			
			// 代收付文件内容
			StringBuilder sbFileContent = new StringBuilder();

			String totalAmt = StringHelper.amountMultiply100(p_reqBat.totalAmt);
			String totalDataSign = ICBC11SignUtil.signWithRSA(actItem.ownKeyStorePath, p_reqBat.totalNum + "|" + totalAmt, getCharset());

			// 汇总信息：总笔数|文件总金额(单位:分)|数字签名串\n
			String tmpReqHeader = MessageFormat.format("{0}|{1}|{2}", p_reqBat.totalNum, totalAmt, totalDataSign);
			sbFileContent.append(tmpReqHeader);
			
			// 文件明细
			while (p_reqBat.readRecord()) {
				if (sbFileContent.length() > 0) {
					sbFileContent.append("\n");
				}
				
				String postScript = p_reqBat.readedDetail.askNumber;

				if(IsNewSequence){
					//保险公司代码（3位）+9位序号+YYYYMMDD，其中日期只能为当日。（必须20位长度，序列号不足9位可左补0）
					postScript = bankFront.corpNo + p_reqBat.readedDetail.askNumber + tmpPaySendDate;
				}
				
				String oppAct = "";
				String oppName = "";
				if ("1988".equals(p_reqBat.reqHeader.transType)) {
					oppAct = p_reqBat.readedDetail.recAct;
					oppName = p_reqBat.readedDetail.recName;
				} else {
					oppAct = p_reqBat.readedDetail.payAct;
					oppName = p_reqBat.readedDetail.payName;
				}
				
				String payAmt = StringHelper.amountMultiply100(p_reqBat.readedDetail.payAmount);
				String cdFlag = "";
				String summary = "";
				if ("1988".equals(p_reqBat.reqHeader.transType)) {
					cdFlag = "1";
					summary = "代付";
				} else {
					cdFlag = "2";
					summary = "代扣";
				}
				
				String tmpYBTFlag = p_reqBat.readedDetail.srcXElement.getSingleText(getBankConfig().getValueAsString("isYBTFlag"));
				if (StringHelper.isNullOrEmpty(tmpYBTFlag)) {
					tmpYBTFlag = "1"; // 默认为银保通
				}
				
				String policyNo = p_reqBat.readedDetail.srcXElement.getSingleText(getBankConfig().getValueAsString("policyNo"));
				
				String busiType = "";
                if ("1988".equals(p_reqBat.reqHeader.transType)) {
                	busiType = getBankConfig().getSetValue("busiType", "002", "1988");// 默认为:002-到期保费支付
                } else {
                	busiType = getBankConfig().getSetValue("busiType", "001", "9188");// 默认为:001-续期保费扣收
                }
				
				String protocolNo = p_reqBat.readedDetail.srcXElement.getSingleText(getBankConfig().getValueAsString("protocolNo"));
				
				// 明细信息:序列号(20位)|客户账号|客户账号户名|交易金额(单位:分)|借贷标志(1借,2贷)|摘要|是否银保通保单(1是,0否)|保单号|业务类型|委托代扣代付协议号\n
				String tmpReqBodyDetail = MessageFormat.format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|{9}", postScript, oppAct, oppName, payAmt, cdFlag, summary, tmpYBTFlag, policyNo, busiType, protocolNo);
				sbFileContent.append(tmpReqBodyDetail);
			}
			
			WriteBankLogLn2("批次文件内容:\r\n" + sbFileContent.toString());
			
			// 上传文件保存本地: ENY(3位)+IAAS(4位)+保险公司代码（3位）+地区号(5位)+网点号(5位)+代理业务编号(9位)+ YYYYMMDD(日期8位)+ AGENT(5位)+批次(10位)+ATS.txt
			
			String busCode = "";
			if ("1988".equals(p_reqBat.reqHeader.transType)) {
				busCode = getBankConfig().getSetValue("busCode", "", "1988");
			} else {
				busCode = getBankConfig().getSetValue("busCode", "", "9188");
			}
			
	    	String reqBatchNoAddComment  = getBankConfig().getValueAsString("ReqBatchNoAddComment");

			
			String tmpUploadFileName = "ENYIAAS" + bankFront.corpNo + actItem.areaCode + actItem.cnapsCode + busCode + tmpPaySendDate + "AGENT" + reqBatchNoAddComment + p_reqBat.reqBatchNO + "ATS.txt";
			String tmpLocalMarkPath = getTempFileDirectory() + File.separator + tmpUploadFileName;
			WriteBankLogLn2("批次文件保存本机路径: " + tmpLocalMarkPath);
			
			if (FileHelper.existFile(tmpLocalMarkPath)) {
				retAts.respCode = "0";
				retAts.respInfo = "本地批次文件已上传,请勿重复上传!";
				retAts.reqSeqID = p_reqBat.reqBatchNO;
				retAts.transState = PaymentState.FAIL_Batch;
				retAts.payInfoCode = FailCode.E9981;
				retAts.writeRetToATS();
				return retAts;
			}
			
			FileHelper.writeFile(tmpLocalMarkPath, sbFileContent.toString(), getCharset());
			
			if (getBankConfig().getValueAsBool("IsEncryption")) {
				String EncryptKey = getBankConfig().getValueAsString("EncryptKey");
				tmpUploadFileName = tmpUploadFileName + ".des";
				tmpLocalMarkPath = FileEncryptionTest.enyFile(tmpLocalMarkPath, EncryptKey);
			}
			

			// 上送银保通服务器
			FtpSet ftpSet = bankFront.getFtpSet("bat");
			
			FtpReceiver ftpReceiver = null;
			String requestType = getBankConfig().getValueAsString("requestType");
			if (requestType != null && "SFTP".equals(requestType)) {
				SftpPortClient sftpPortClient = new SftpPortClient(ftpSet);
				String sftpFilePath = StringHelper.trimEnd(ftpSet.upDir, "/") + "/" + tmpUploadFileName;
				ftpReceiver = sftpPortClient.uploadFile("", tmpLocalMarkPath, sftpFilePath);
				sftpPortClient.disconnect();
			} else {
				FtpPortClient ftpPortClient = new FtpPortClient(ftpSet);
	            ftpReceiver = ftpPortClient.uploadFile(tmpLocalMarkPath, tmpUploadFileName);
	            ftpPortClient.disconnect();
			}
			
			retAts.respCode = "0";
            retAts.reqSeqID = p_reqBat.reqBatchNO;
            if (!ftpReceiver.isCompleted) {
                retAts.respCode = "-1";
                retAts.respInfo = ftpReceiver.connMsg;
            } else if (ConnState.FAIL.equals(ftpReceiver.connState)) {
            	retAts.respInfo = "上传失败";
            	retAts.transState = "BatchFailed";
            	retAts.payInfoCode = "E9999";
            } else {
            	retAts.respInfo = "上传成功";
            	retAts.transState = "Uploaded";
            	retAts.payInfoCode = "I4001";
            }
		} catch (Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		}

		retAts.writeRetToATS();
		return retAts;
	}

	/**
	 * 批量代收付状态查询
	 * 
	 * <p>功能描述:</p>
	 * <ul>
	 * 	<li>1、文件名命名规则:</li>
	 * 		<li>ENY+保险公司代码+银行代码(01)+地区号+网点号+代理业务编号+YYYYMMDD+AGENT+批次+ATS.txt</li>
	 *  <li>2、文件内容格式说明:</li>
	 *  <li>1)  汇总记录：</li>
	 *  	<li>文件中成功总笔数|文件中代收付成功的记录的金额总和\n</li>
	 *  <li>2)  明细记录：</li>
	 *  	<li>序列号(20位)|客户账号|交易金额(单位:分)|借贷标志(1借,2贷)|摘要|错误代码|失败原因\n</li>
	 * </ul>
	 * 
	 * @param p_reqQryBat
	 * @return
	 * @throws Exception
	 */
	public RetAtsQryBatPayRec d_QryBatPayRec(ReqQryBatPayRec p_reqQryBat) throws Exception {
		RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_reqQryBat.reqHeader);
		retAts.reqSeqID = p_reqQryBat.reqBatchNO;
		
    	boolean IsNewSequence  = getBankConfig().getValueAsBool("IsNewSequence");
		
		try {
			ActSetItem actItem = this.getBankConfig().getActSetItem(p_reqQryBat.ownAct, "bat");
			if (actItem == null) {
				retAts.respCode = "-1";
				retAts.respInfo = "未找到账号:[" + p_reqQryBat.ownAct + "]商户配置信息!";
				retAts.writeAfterDetail();
				return retAts;
			}
			
			// 下载文件名命名规则:ENY+保险公司代码+01+地区号+网点号+代理业务编号+YYYYMMDD+BATCHRET+批次+ATS.txt
			String tmpPaySendDate = Format.Date8Format.format(p_reqQryBat.getBgnDateTime());
			
			String busCode = "";
			if ("1998".equals(p_reqQryBat.reqHeader.transType)) {
				busCode = getBankConfig().getSetValue("busCode", "", "1988");
			} else {
				busCode = getBankConfig().getSetValue("busCode", "", "9188");
			}
			
			String tmpDownFileName = "ENY" + bankFront.corpNo + "01" + actItem.areaCode + actItem.cnapsCode + busCode + tmpPaySendDate + "BATCHRET" + p_reqQryBat.reqBatchNO + "ATS.txt";
			if (getBankConfig().getValueAsBool("IsEncryption")) {
				tmpDownFileName = tmpDownFileName + ".des";
			}
			String tmpLocalMarkPath = createTempFileDirectory() + File.separator + tmpDownFileName;
			WriteBankLogLn2("批次结果文件保存本地路径: " + tmpLocalMarkPath);

			FtpSet ftpSet = bankFront.getFtpSet("bat");
			FtpReceiver ftpReceiver = null;
			String requestType = getBankConfig().getValueAsString("requestType");
			if (requestType != null && "SFTP".equals(requestType)) {
				String sftpFilePath = StringHelper.trimEnd(ftpSet.downDir, "/") + "/" + tmpDownFileName;
				WriteBankLogLn2("待下载SFTP服务器文件路径:\r\n" + sftpFilePath);
				SftpPortClient sftpPortClient = new SftpPortClient(ftpSet);
	            ftpReceiver = sftpPortClient.downloadFile("", sftpFilePath, tmpLocalMarkPath);
	            sftpPortClient.disconnect();
			} else {
				FtpPortClient ftpPortClient = new FtpPortClient(ftpSet);
				ftpReceiver = ftpPortClient.downloadFile(tmpDownFileName, tmpLocalMarkPath);
				ftpPortClient.disconnect();
			}
			
			if (ftpReceiver.isCompleted) {
            	String tmpStrRet = FileHelper.readFileText(tmpLocalMarkPath, getCharset());
            	WriteBankLogLn2("本地批次结果文件内容:\r\n" + tmpStrRet);
            	
    			// 解密文件
    			if (getBankConfig().getValueAsBool("IsEncryption")) {
    				String EncryptKey = getBankConfig().getValueAsString("EncryptKey");
    				tmpLocalMarkPath = FileEncryptionTest.decFile(tmpLocalMarkPath, EncryptKey);
    				tmpStrRet = FileHelper.readFileText(tmpLocalMarkPath, getCharset());
    				WriteBankLogLn2("结果文件内容（解密后）:\r\n" + tmpStrRet);
    			}
            	
            	if (StringHelper.hasAnyChar(tmpStrRet)) {
            		retAts.respCode = "0";
					retAts.reqSeqID = p_reqQryBat.reqBatchNO;
					
					// 整批失败
					String[] tmpHeadArray = tmpStrRet.split("\n");
					if ((tmpHeadArray != null) && (tmpHeadArray.length == 2) && ("2000".equals(tmpHeadArray[1].split("\\|")[5]) || "3000".equals(tmpHeadArray[1].split("\\|")[5]))) {
						String[] errArray = tmpHeadArray[1].split("\\|");
						retAts.transState = errArray[5];
						retAts.payInfoCode = errArray[5];
						retAts.respInfo = errArray[6];
						retAts.writeAfterDetail();
						return retAts;
					}
					
					StringReader strReader = new StringReader(tmpStrRet);
					BufferedReader tmpReader = new BufferedReader(strReader);
					tmpReader.readLine();
					
					while(true) {
						String eachline = tmpReader.readLine();
						if(StringHelper.isNullOrEmpty(eachline)){
							break;
						}
						if (eachline.indexOf("|") > 0) {
							// 明细记录:序列号|客户账号|交易金额(单位:分)|借贷标志|摘要|错误代码|失败原因\n
							String[] bodyValues = eachline.split("\\|");
							if (bodyValues.length == 7) {
								RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();
								
								if(p_reqQryBat.reqHeader.transType.equals("1998")){
									tmpRetDetail.recAct = bodyValues[1];
								} else if(p_reqQryBat.reqHeader.transType.equals("9198")){
									tmpRetDetail.payAct = bodyValues[1];
								}
								
								tmpRetDetail.postScript = bodyValues[0];
								if(IsNewSequence){
									tmpRetDetail.postScript = bodyValues[0].substring(3, 11);
								}								
								tmpRetDetail.payAmount = StringHelper.amountDivide100(bodyValues[2]);
								tmpRetDetail.result = StringHelper.joinNotEmpty("+", "DTNEW", bodyValues[5]);
								//tmpRetDetail.payInfoCode = bodyValues[5];
								tmpRetDetail.payInfoCode = bodyValues[6];
								tmpRetDetail.memo = bodyValues[6];
		                        
								retAts.writeRetDetail(tmpRetDetail);
							} else {
								retAts.respCode = "-1";
			            		retAts.respInfo = "每行明细应为7列，实际为：" + bodyValues.length;
							}
						} else {
							retAts.respCode = "-1";
		            		retAts.respInfo = "银行返回明细数据格式非法!";
						}
					}
            	} else {
            		retAts.respCode = "-1";
            		retAts.respInfo = "本地批次结果文件内容为空!";
            	}
            } else {
            	retAts.respCode = "-1";
    			retAts.respInfo = "退保结果文件下载失败:" + ftpReceiver.connMsg;
            }
		} catch (Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		}
		
		retAts.writeAfterDetail();
		return retAts;
	}
}
